<?php
/**
 * Base_App
 *
 * LICENSE
 *
 * This source file is subject to the new CC-GNU LGPL
 * It is available through the world-wide-web at this URL:
 * http://creativecommons.org/licenses/LGPL/2.1/
 *
 * @category   Base_App
 * @copyright  Copyright (c) 2009 Alexander fanatique* Thomas (me@alexander-thomas.net)
 * @license    http://creativecommons.org/licenses/LGPL/2.1/
 */
class Base_App_Initialization
{
	private static $_instance = null;

	/**
	 * Implementation of the singleton pattern.
	 */
	public static function getInstance()
	{
	    if (null === self::$_instance) {
	        self::$_instance = new self();
	    }

	    return self::$_instance;
	}
	
	/**
	 * Stores the path of the application in to the registry.
	 */
	public function registerApplicationPath($applicationPath){
		$this->_register('applicationPath', $applicationPath);
	}

	/** 
	 * Detects the current environment setting for the application by parsing
	 * application/config/environment.ini
	 * @param $applicationPath - Absolute path to the application
     * @throws Base_App_Initialization_Exception
	 */
	public function getEnvironment(){
		$env = null;
		if (Zend_Registry::isRegistered('environment')) {
		    $env = Zend_Registry::get('environment');
		}

		if($env != null){
			return $env;
		}else{
			$appPath = Zend_Registry::get('applicationPath');
	        try{
	            $env = new Zend_Config_Ini($appPath . 'Config/environment.ini');
	        	$this->_register('environment', $env->environment);
	        }catch(Zend_Config_Exception $e){
	            throw new Base_App_Initialization_Exception(Base_App_Initialization_Exception::ENVIRONMENT);
	        }
			return $env->environment;			
		}
	}
	
	/** 
	 * Detects the current build number by parsing
	 * application/config/build.ini
	 * @param $applicationPath - Absolute path to the application
     * @throws Base_App_Initialization_Exception
	 */
	public function getBuildNumber(){
		$build = null;
		$appPath = Zend_Registry::get('applicationPath');
	    try{
			$build = new Zend_Config_Ini($appPath . 'Config/build.ini');
			$this->_register('build', $build->build);
		}catch(Zend_Config_Exception $e){
			throw new Base_App_Initialization_Exception(Base_App_Initialization_Exception::BUILDNUMBER);
		}
	}
	
	
    /**
     * Loads the application config file and saves it into the registry.
	 * @param $environment - The environment setting to use
     * @throws Base_App_Initialization_Exception
     */
    public function setupApplicationConfig($environment){
		$appPath = Zend_Registry::get('applicationPath');
        try{
          $appConfig = new Zend_Config_Ini($appPath . 'Config/application.ini', $environment);  
        }catch(Zend_Config_Exception $e){
            Base_App_Debug::dd($e);
			throw new Base_App_Initialization_Exception(Base_App_Initialization_Exception::APPLICATION_CONFIGURATION);
        }
        $this->_register('applicationConfiguration', $appConfig);
		return $appConfig;
    }
    
    /**
     * Instatiates a Zend_Log logger and saves it into the registry.
     * @throws Base_App_Initialization_Exception
     */
    public function setupLogger(){
		$appPath = Zend_Registry::get('applicationPath');
		$appConfig = Zend_Registry::get('applicationConfiguration');
		
		        try {
		            $logPath = $appPath . '/' . $appConfig->path->logs;
		            $writer = new Zend_Log_Writer_Stream($logPath . $appConfig->log->filename);  
		$format = '%timestamp% %priorityName% (%priority%): %message%' . PHP_EOL;
		       	$formatter = new Zend_Log_Formatter_Simple($format);
		            
		            $writer->setFormatter($formatter);
		            
		            $logger = new Zend_Log();
		            $logger->addWriter($writer);
		        } catch (Zend_Exception $e) {
		           	Base_App_Debug::d($e);
			throw new Base_App_Initialization_Exception(Base_App_Initialization_Exception::LOGGER);
		        }
		
		        $this->_register('log', $logger);
    }

    /**
     * Setting up a database connection using Zend_db
     * @throws Base_App_Initialization_Exception
 	 * @todo optional parameter socket 
     */ 
    public function setupDb(){
		$appConfig = Zend_Registry::get('applicationConfiguration');

		try{
			$db = Zend_Db::factory($appConfig->db->driver, array(
	            'host'     => $appConfig->db->host,
				'port'     => $appConfig->db->port,
	            'username' => $appConfig->db->username,
	            'password' => $appConfig->db->password,
	            'dbname'   => $appConfig->db->dbname
	        ));

			$db->query($appConfig->db->initialization_parameters);	
					
		}catch(Zend_Db_Exception $e){
			Base_App_Debug::dd($e);
			$logger = Zend_Registry::get('log');
			$logger->err('Database initialization failed: ' . $e->getMessage() . ' ' . print_r($e->getTrace(), true));
            throw new Base_App_Initialization_Exception(Base_App_Initialization_Exception::DATABASE);			
		}
		if($appConfig->db->cache == 1){
			$appPath = Zend_Registry::get('applicationPath');
			//Cache for Table Metadata
			$frontendOptions = array('automatic_serialization' => true);
			$backendOptions  = array('cache_dir' => $appPath . $appConfig->path->cache);
			$cache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions);
			Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);			
		}
        $this->_register('db', $db);
    }

	/**
	 * Sets up acl roles and rules
	 */
    public function setupAcl() {
		$appConfig = Zend_Registry::get('applicationConfiguration');
		$appPath = Zend_Registry::get('applicationPath');
		if($appConfig->acl->state != 0){
			/**Check for cached Zend_Acl object*/
			$cachePath = $appPath . $appConfig->path->cache;
			$cachedFile =  $cachePath . $appConfig->acl->cached->filename;
        	$acl = Base_App_Acl::getInstance();#$this->_setupAcl();
			$aclCache = (bool) $appConfig->acl->cache;

			if($aclCache === true){
				try{
					$acl->loadFromCache($cachedFile);
				}catch(Base_App_Initialization_Exception $e){
					if($e->getCode() == Base_App_Initialization_Exception::ACL_CACHE){
						$acl->rebuildResources();
					}
				}catch(Exception $e){
					/**
				 	 * @todo Error handling
				 	 */
				}
			}else{
				$acl->rebuildResources();
			}
        	$this->_register('acl', $acl);
		}
    }
    
	/**
	 *
	 */
	public function setupSession(){
		Zend_Session::start();
	}
    
    /**
     * Sets action and view helper paths.
     */
    public function setupHelperPaths() {
		$appPath = Zend_Registry::get('applicationPath');
		Zend_Controller_Action_HelperBroker::addPath($appPath . 'Controllers/Action/Helper', 'Controllers_Action_Helper_');
    }
	/**
	 * @todo outsource module definition
	 * @return 
	 * @param object $front
	 * @param object $environment
	 */
	public function setupFrontController($front, $environment){
		$appPath = Zend_Registry::get('applicationPath');
		$front->setControllerDirectory(array(
		    'default' => $appPath . 'Controllers/default'
		));
		$front->setParam('useDefaultControllerAlways', true);
		if($environment != 'production') $front->throwExceptions(true);
	}
    
    public function setupTranslation(){
		$appConfig = Zend_Registry::get('applicationConfiguration');
		$appPath = Zend_Registry::get('applicationPath');
		$cache = Zend_Cache::factory('Core', 'File');
		#Zend_Translate::setCache($cache);
        try {
			$translate = new Zend_Translate('csv', $appPath. $appConfig->path->translations . 'en.csv', 'en');
			$translate->addTranslation($appPath. $appConfig->path->translations .  'en.csv', 'en');
			$this->_register('translate', $translate);
		} catch (Exception $e) {
    		//Base_App_Debug::dd($e);
		}
    }

	/**
	 * Parses the routes.xml file and sets up custom routes
	 */
	public function setupRoutes(Zend_Controller_Router_Rewrite $router){
		$appConfig = Zend_Registry::get('applicationConfiguration');
		$appPath = Zend_Registry::get('applicationPath');
		$configPath = $appPath . $appConfig->path->config;
		$file = $configPath . 'routes.xml';
		$routes = new Zend_Config_Xml($file, null);
		if(isset($routes->useless_tag->route->name)){
			$route = $routes->useless_tag->route;
			count($route->param) > 1 ? $params = implode('/:', $route->param->toArray()) : $params = $route->param;
			$path = $route->path . '/:' . $params;
			$module = (isset($route->module)) ? $route->module : 'default';
			$router->addRoute(
			    $route->name,
			    new Zend_Controller_Router_Route($path, array('module' => $module, 'controller' => $route->controller, 'action' => $route->action))
			);			
		}else{
			foreach($routes->useless_tag->route AS $route){
				count($route->param) > 1 ? $params = implode('/:', $route->param->toArray()) : $params = $route->param;
				$path = $route->path . '/:' . $params;
				$module = (isset($route->module)) ? $route->module : 'default';
				$router->addRoute(
				    $route->name,
				    new Zend_Controller_Router_Route($path, array('module' => $module, 'controller' => $route->controller, 'action' => $route->action))
				);	
			}			
		}
	}
   
    /**
     * Simple wrapper for saving a value into the Zend_Registry
     * @param string $key Name of the Object in the registry.
     * @param object $value Value of tªe object in the registry.
     */
    private function _register($key, $value){
        Zend_Registry::set($key, $value);
    }
}
?>
